package com.demo.test.leak

import android.app.Activity
import android.os.Bundle
import android.os.SystemClock
import android.util.Log
import android.widget.TextView
import com.demo.Tags
import com.demo.component.LeakingThread2
import com.fortest.R
import java.util.concurrent.atomic.AtomicReference

/**
泄露方式：Thread的本地变量
泄露原因：Activity开启了一个新线程执行任务，
在Activity中把this放到Thread的一个变量中，使得这个Activity会一直被新线程长期持有，
LeakingThread2这个线程一旦执行run方法，马上就把自己挂起来了，等待notify()或者notifyAll()，然而没有其它线程来唤醒它，因此它会一直活着，所持有的资源也不会释放
当Activity退出时，任务还没执行完，新线程一直持有Activity，导致Activity泄露。

泄露报告　－－　StrictMode：
2020-05-24 21:57:09.977 16550-16550/com.example.myapplication E/StrictMode: class com.demo.test.leak.ActivityLeakJ_Thread4; instances=2; limit=1
android.os.StrictMode$InstanceCountViolation: class com.demo.test.leak.ActivityLeakJ_Thread4; instances=2; limit=1
at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)

泄露报告　－－　LeakCanary：
98995 bytes retained by leaking objects
Displaying only 1 leak trace out of 3 with the same signature
Signature: af6a11ff3f162eb6427ac21b5e766b2e2385ea0
┬───
│ GC Root: Local variable in native code
│
├─ com.demo.component.LeakingThread2 instance
│    Leaking: UNKNOWN
│    Thread name: 'Leaking local variables'
│    ↓ LeakingThread2.ref
│                     ~~~
├─ java.util.concurrent.atomic.AtomicReference instance
│    Leaking: UNKNOWN
│    ↓ AtomicReference.value
│                      ~~~~~
╰→ com.demo.test.leak.ActivityLeakJ_Thread4 instance
​     Leaking: YES (ObjectWatcher was watching this because com.demo.test.leak.ActivityLeakJ_Thread4 received Activity#onDestroy() callback and Activity#mDestroyed is true)
​     key = 317e327e-c579-4ec7-93ee-67c210717a69
​     watchDurationMillis = 58755
​     retainedDurationMillis = 53753
 **/
class ActivityLeakJ_Thread4 : Activity() {
    val TAG = Tags.leakThread2
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_leak_common)
        val textView = findViewById<TextView>(R.id.helper_text)
        textView.text = "泄露方式：Thread的本地变量\n" +
                "泄露原因：Activity开启了一个新线程执行任务，\n" +
                "在Activity中把this放到Thread的一个变量中，使得这个Activity会一直被新线程长期持有，\n" +
                "LeakingThread2这个线程一旦执行run方法，马上就把自己挂起来了，等待notify()或者notifyAll()，然而没有其它线程来唤醒它，因此它会一直活着，所持有的资源也不会释放\n" +
                "当Activity退出时，任务还没执行完，新线程一直持有Activity，导致Activity泄露。"
        Log.d(TAG, "线程的本地变量，导致内存泄露")


        // Leak from local variable on thread
        val ref = AtomicReference(this)

        val thread = LeakingThread2()
        thread.setRef(this)
        thread.name = "Leaking local variables"
        thread.start()
    }


}
